package com.sixeco.apigetway.common;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sixeco.apigetway.handle.BcHttpHandle;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.ScheduledFuture;

/**
 * 
 * @author tianzhenjiu
 *
 */
public class WriteProcessListener implements GenericFutureListener<ChannelFuture> {

	Logger logger = LoggerFactory.getLogger(getClass());

	final Channel bcChannel;

	final int times;

	final FullHttpRequest request;
	

	public WriteProcessListener(Channel bcChannel, int times, FullHttpRequest request) {
		super();
		this.bcChannel = bcChannel;
		this.times = times;
		this.request = request;
	}

	@Override
	public void operationComplete(ChannelFuture future) throws Exception {

		
		
		if(bcChannel==null) {
			logger.warn("channel不能为空");
			return;
		}
		
		Channel bcChannel = this.bcChannel;
		if (future.isSuccess()) {
			
			/**
			 * 开启新的定时任务
			 * rewrite 执行完毕之后肯定会执行listener
			 * 
			 */
			ScheduledFuture<?> scheduledFuture=bcChannel.eventLoop().schedule(()->{
				reWrite();
			},5,TimeUnit.SECONDS);
			
			
			scheduledFuture.addListener((lw)->{
				
				
				
				/**
				 * 如果任务被取消了，引用计数器就是1，必须释放内存
				 * 
				 * 如果任务被执行了，引用计数器经过bindAndWriteBcActiveChannel->2
				 * 经过writeandflush->1 
				 * 所以任务执行完成了引用计数器也是1，这个留在下次使用
				 */
				if(lw.isCancelled()) {
					
					if(request.refCnt()>0&&request.release()) {
						logger.debug("释放原有内存{}",bcChannel);
					}
				}
				

				if(!lw.isSuccess()){
					
					if(!lw.isCancelled()) {						
						logger.warn("失败",lw.cause());
					}
				}
				
			});
			
			
			/**
			 * 如果channel上已经有了定时任务，就要取消掉
			 * 这里只支持一个http包重写
			 */
			ScheduledFuture<?> oldFuture=bcChannel.attr(CommonVar.Proxy.reWriteFuture).getAndSet(scheduledFuture);
			if(oldFuture!=null) {
				oldFuture.cancel(false);
				logger.debug("取消原有任务");
			}

		} else {
			reWrite();
		}

	}
	

	/**
	 * 重写
	 */
	private void reWrite() {

		logger.info("写入失败,重写");

		
		AttributeKey<Channel> abChannelAttr = CommonVar.Proxy.abChannelAttr;
		
		if (!bcChannel.hasAttr(abChannelAttr)) {
			logger.warn("没有前置服务了{}", bcChannel);
			return;
		}
		
		Channel abChannel=bcChannel.attr(abChannelAttr).get();
		
		/**
		 * 既然原有的channel写入不成功就需要关闭然后重写路由选择channel
		 */
		bcChannel.close();
		
		if (times >= CommonVar.HttpChunk.reWriteTimes) {
			logger.info("重写失败次数太多了{}", bcChannel);

			FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
					HttpResponseStatus.BAD_GATEWAY, Unpooled.wrappedBuffer(CommonVar.HttpChunk.proxyErrr));
			CommonIO.getInstance().writeMsgAndClose(abChannel, response);
			return;
		}


		CommonIO.getInstance().bindAndWriteBcActiveChannel(abChannel, times+1, request);

	}

}
